"""
Copyright (c) 2015, The Linux Foundation. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.
    * Neither the name of The Linux Foundation nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""

from print_out import print_out_str
from parser_util import register_parser, RamParser
import ipc_logging
import os
import sys

LOG_DEBUG = 3
LOG_INFO = 2
LOG_WARNING = 1
LOG_ERROR = 0

strUsage = """\
python ramparse.py --print-ipc-logging <options>

Normal Usage
------------
IPC Logging Extraction can be performed by providing ramdump files to the Linux
Ramdump Parser in the normal fashion. The output is written into the ipc_logging
directory, which is created automatically if it doesn't exist. The IPC Logging
Extraction module's internal logging can be found in
ipc_logging/logging_output.txt.

skip
-----
If you're parsing everything using --everything or -x and you wish to skip IPC
log extraction, use the --ipc-skip option.

Example:
\tpython ramparse.py <args> --everything --ipc-skip

debug
-----
To extract the IPC logs in debug mode, use the --ipc-debug flag. This will
produce the binary of each individual log page, which can be given to the test
command (see below). It will also turn on debug logging.

Example:
\tpython ramparse.py <args> --ipc-debug

test
----
To use the "test" functionality of the IPC Logging Extraction module, provide
the --ipc-test option for each file to test and the IPC Logging version. These
files must be log pages generated by extracting IPC logs in debug mode
(--ipc-debug).

Be sure to use the --64-bit option correctly. The --ipc-test command will fail
if this option is used incorrectly. This is because the start of the actual page
data depends upon the size of internal data structures and pointers that can
vary with machine size. This information is stored in the logging context for
automated extraction (i.e. the "parse" command), but needs to be provided
manually for the "test" command.

Examples:
\tpython ramparse.py <args> --print-ipc-logging --ipc-test log_page_1.bin --ipc-test log_page_2.bin --ipc-test 0
\tpython ramparse.py <args> --64-bit --print-ipc-logging --ipc-test log_page_1.bin --ipc-test log_page_2.bin --ipc-test 1

help
----
To write this help message, use the --ipc-help option.

Example:
\tpython ramparse.py <args> --ipc-help
"""

class IPCLoggingOptions:
    """
    This class emulates the options object built by optparse in ipc_logging.
    """
    def __init__(self):
        self.args = []
        self.debug_enabled = False
        self.output_dir = "./ipc_logging"
        self.verbosity = LOG_INFO
        self.quiet = False
        self.cmd = "parse"
        self.arch64 = False

@register_parser('--print-ipc-logging', 'Print all the IPC information')
class IPCParse(RamParser):
    def parse(self):
        options = IPCLoggingOptions()

        if self.ramdump.ipc_log_skip:
            msg = "Skipping IPC log extraction."
            if self.ramdump.use_stdout:
                sys.stderr.write(msg + "\n")
            else:
                sys.stderr.write(msg + " ")
            return

        if self.ramdump.ipc_log_test:
            # Do not iterate over the last element in the list as it contains
            # the version and will fail the os.path.exists check
            for a in self.ramdump.ipc_log_test[:-1]:
                if not os.path.exists(a):
                    msg = \
                    "IPC Test file {0} does not exist".format(a)
                    raise Exception(msg)

            options.cmd = "test"
            options.args = self.ramdump.ipc_log_test
            options.arch_64 = self.ramdump.arm64

        if options.cmd == 'parse':
            start_sorted_files = self.ramdump.ebi_files
            start_sorted_files.sort(key=lambda ram_file_tup: ram_file_tup[1])
            for ram_file_tuple in start_sorted_files:
                fd, start, end, path = ram_file_tuple
                options.args.append(str(path)+':'+str(start))

        if self.ramdump.ipc_log_debug:
            options.verbosity = LOG_DEBUG
            options.debug_enabled = self.ramdump.ipc_log_debug

        if self.ramdump.ipc_log_help:
            options.cmd = "help"

        ipc_logging.configure_logging(options, self.ramdump.use_stdout)

        # Return value of set_output_directory() is not checked here because
        # set_output_directory() only returns NULL if options.output_dir is not
        # set, and options.output_dir is always set per the IPCLoggingOptions
        # constructor
        ipc_logging.set_output_directory(options)

        if options.cmd == 'parse':
            ipc_logging.cmdParse(options)
            print_out_str("Wrote parse output to ipc_logging directory")
        elif options.cmd == 'test':
            ipc_logging.cmdTest(options)
            print_out_str("Wrote test output to ipc_logging directory")
        else:
            print strUsage
